BehaviourクラスのEnableをスクリプトから切り替えるEditor機能

November 15, 2022


BehaviourEnableSwitcher クラスがアクティブ化された時、指定したBehaviourクラスのEnableを自動で切り替える拡張機能です

Timeline 上から Audio Low Pass Filter の機能をOn/Off したくて作成。 (なんか他にやりようはありそうだけど…)

コード全部

using UnityEngine;
using UnityEngine.UIElements;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.UIElements;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Core.Common
{
	/// <summary>
	/// BehaviourクラスのEnableをスクリプトから切り替える
	/// </summary>
	[ExecuteAlways]
	public class BehaviourEnableSwitcher : MonoBehaviour
	{
		/* Define & Class */

		public enum ApplyType
		{
			Active,	// OnEnable/OnDisable時に適用する
		}


		/* Public Field */


		/* Private Field */

		[SerializeField] private GameObject _targetGameObject;
		[SerializeField] private ApplyType _applyType;
		[SerializeField] private string _targetType;

		private bool _isInitialized;
		private List<Behaviour> _allComponents = new List<Behaviour>();
		private int _index;


		/* Property */


		/* Public Method */


		/* Pritvate Method */

		private void UpdateTarget()
		{
			if (_targetGameObject == null)
			{
				return;
			}

			_allComponents = _targetGameObject.GetComponents<Behaviour>().ToList();

			_index = Mathf.Max(_allComponents.FindIndex(x => x.GetType().Name == _targetType), 0);
			_isInitialized = true;
		}

		private void SetTargetEnable(bool isEnable)
		{
			if (!_isInitialized) return;

			var component = _allComponents[_index];
			component.enabled = isEnable;
		}

		/* Monobehaviour */

		private void OnEnable()
		{
			if (_applyType == ApplyType.Active)
			{
				SetTargetEnable(true);
			}
		}

		private void OnDisable()
		{
			if (_applyType == ApplyType.Active)
			{
				SetTargetEnable(false);
			}
		}

		private void Awake()
		{
			UpdateTarget();
		}

		private void Start()
		{
		}

		private void Update()
		{
		}

		private void OnDestroy()
		{
		}

#if UNITY_EDITOR
		[CustomEditor(typeof(BehaviourEnableSwitcher))]
		public class ComponentEnableSwitcherEditor : Editor
		{
			public override VisualElement CreateInspectorGUI()
			{
				var switcher = target as BehaviourEnableSwitcher;
				switcher.UpdateTarget();

				var root = new VisualElement();

				// ターゲットとなるGameObject
				var targetGameObjectProp = serializedObject.FindProperty(nameof(switcher._targetGameObject));
				var targetTypeProp = serializedObject.FindProperty(nameof(switcher._targetType));

				var targetGameObjectField = new PropertyField(targetGameObjectProp);
				targetGameObjectField.RegisterValueChangeCallback(_ => 
				{
					// 値が更新されたらUpdateTargetメソッドを呼び出してリストを更新してもらう
					switcher.UpdateTarget();
				});


				// 適用タイプ
				var applyTypeProp = serializedObject.FindProperty(nameof(switcher._applyType));
				var applyTypeField = new PropertyField(applyTypeProp);


				// 文字列に変換して選択できるようにする
				var allComponents = switcher._allComponents.Select(x => x.GetType().Name).ToList();

				var componentMenu = new DropdownField("Target", allComponents, switcher._index);
				componentMenu.RegisterValueChangedCallback(ev => 
				{
					switcher._index = allComponents.FindIndex(x => x == ev.newValue);

					targetTypeProp.stringValue = ev.newValue;

					serializedObject.ApplyModifiedProperties();
				});


				root.Add(targetGameObjectField);
				root.Add(applyTypeField);
				root.Add(componentMenu);
				root.Bind(serializedObject);

				return root;
			}
		}
#endif
	}
}

Target Game Object には、切り替えたいComponentがついてるGameObjectを指定。 TargetでComponent名をリストから選択します

866277A7ACB798890F4C75A9D2CB6A9F

自分がアクティブ/非アクティブされるたびにTarget の Enable が切り替わる。 FA2DAC0F212BF1BC6B7C7A414543DE1F

Timelineで使うときは Control Track を利用してアクティブ/非アクティブ 切り替えてもらって制御

3FDC010F4AE305CA633330D3C653A88B

「追記」 _targetGameObject に値を設定した直後、リストが生成されてもインスペクタに反映されない不具合見つけたので後日修正予定